Skip to content

Conversation

@nikwithak
Copy link
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-24178

📔 Objective

Forces the focus to the close button at the top of a dialog when it is first rendered. Affects all uses of the dialog component.

📸 Screenshots

pm-24178_modal_focus.mov

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@claude
Copy link

claude bot commented Oct 16, 2025

Claude finished @nikwithak's task —— View job


PR Review Complete

Todo List

  • Analyze PR diff and changed files
  • Review dialog component focus implementation
  • Investigate unrelated vault file changes
  • Check for potential issues (bugs, security, performance)
  • Provide comprehensive feedback

Summary of Changes

This PR contains changes to two separate features that should be split into separate pull requests:

  1. Dialog Modal Focus Fix (PM-24178): Adding cdkFocusInitial to the close button in dialog.component.html
  2. Vault Attachment Revision Date (appears to be from a different ticket): Adding lastKnownRevisionDate to attachment-related APIs

⚠️ Critical Issues

1. Mixed Concerns - PR Contains Unrelated Changes

Severity: High

This PR mixes two completely separate features:

  • Dialog focus fix (dialog.component.html) - matches the PR title/objective
  • Vault attachment changes (4 vault-related files) - unrelated to dialog focus

Why this is problematic:

  • Violates single responsibility principle for PRs
  • Makes code review harder
  • Complicates git history and potential reverts
  • Makes it unclear which Jira ticket these vault changes belong to

Recommendation: Split this into two separate PRs:

  1. Keep only the dialog.component.html change in this PR
  2. Move all vault-related changes to a new PR with proper Jira ticket reference
Files that should be in a separate PR
  • libs/common/src/vault/models/request/attachment.request.ts
  • libs/common/src/vault/models/request/cipher.request.ts
  • libs/common/src/vault/services/cipher.service.ts
  • libs/common/src/vault/services/file-upload/cipher-file-upload.service.ts

🔍 Dialog Focus Implementation Review

Changes

File: libs/components/src/dialog/dialog/dialog.component.html:41

<button
  type="button"
  bitIconButton="bwi-close"
  buttonType="main"
  size="default"
  bitDialogClose
  [label]="'close' | i18n"
  cdkFocusInitial  
></button>

✅ Good Practices

  • Uses Angular CDK's cdkFocusInitial directive for focus management
  • Works with existing cdkTrapFocus and cdkTrapFocusAutoCapture on the section element
  • Simple, declarative approach using Angular CDK best practices

🤔 Potential Issues

Issue 1: Focus Behavior When Close Button is Hidden

Severity: Medium

The close button is conditionally rendered:

@if (!this.dialogRef?.disableClose) {
  <button ... cdkFocusInitial></button>
}

Problem: When disableClose is true, the close button doesn't render, and cdkFocusInitial has no effect. Focus will fall back to CDK's default behavior (first focusable element).

Impact: Inconsistent focus behavior across different dialog configurations.

Recommendation:

  • Document this behavior in the component
  • Consider if this is the intended behavior for all dialog use cases
  • Test with dialogs that have disableClose: true

Issue 2: No Consideration for Dialog Content with Input Fields

Severity: Low-Medium

Scenario: Dialogs with forms where users expect focus on the first input field (e.g., "Add Item" dialog).

Problem: Users will need to tab backward from the close button to reach the first form field, which is counterintuitive for form-based dialogs.

Recommendation:

  • Consider making focus target configurable per dialog instance
  • Or add documentation explaining this behavior and how to override it
  • Example use case that might be affected:
    // Dialog with a search input might want focus on the input, not close button
    dialogRef.open(SearchDialogComponent, {
      // Need a way to specify focus target
    });

Issue 3: Accessibility Considerations

Severity: Low

Screen reader experience:

  • Focusing on close button first means screen reader users hear "close" before hearing the dialog title/purpose
  • ARIA Authoring Practices recommend focusing on dialog title or first focusable element in content

Recommendation:

  • Test with screen readers (NVDA, JAWS, VoiceOver)
  • Consider if this aligns with WCAG 2.1 guidelines
  • Document the accessibility reasoning in code comments

🔍 Vault Changes Review (Should be separate PR)

Click to expand review of vault changes

Changes Overview

Adds lastKnownRevisionDate field to attachment operations for optimistic concurrency control.

Files Modified

  1. attachment.request.ts - Added lastKnownRevisionDate: Date property
  2. cipher.request.ts:204 - Set attachmentRequest.lastKnownRevisionDate = cipher.revisionDate
  3. cipher.service.ts:1747-1753,1760,1764 - Fetch cipher and append revision date to FormData
  4. cipher-file-upload.service.ts:36 - Set lastKnownRevisionDate: cipher.revisionDate

🚨 Security Considerations

Issue 1: Potential Type Safety Issue

Severity: Medium

File: attachment.request.ts:8

lastKnownRevisionDate: Date;

Problem:

  • File has // @ts-strict-ignore at the top
  • The property is typed as Date but serialized to ISO string when sent to API
  • No validation that the Date is actually set before being used

Lines cipher.service.ts:1753, 1760, 1764:

fd.append("lastKnownRevisionDate", lastKnownRevisionDate.toISOString());

Risk: If lastKnownRevisionDate is null/undefined, this will throw a runtime error.

Recommendation:

// Add null check
if (lastKnownRevisionDate) {
  fd.append("lastKnownRevisionDate", lastKnownRevisionDate.toISOString());
}

Issue 2: Missing Null Safety in cipher.service.ts

Severity: Medium

Lines 1747-1750:

const cipher = await firstValueFrom(
  this.cipherViews$(activeUserId.id).pipe(
    filterOutNullish(),
    map((ciphers) => ciphers.find((c) => c.id === cipherId)),
  ),
);
const lastKnownRevisionDate = cipher.revisionDate;

Problem:

  • ciphers.find() can return undefined if cipher is not found
  • No null check before accessing cipher.revisionDate

Recommendation:

const cipher = await firstValueFrom(
  this.cipherViews$(activeUserId.id).pipe(
    filterOutNullish(),
    map((ciphers) => ciphers.find((c) => c.id === cipherId)),
  ),
);
if (!cipher) {
  throw new Error(`Cipher not found: ${cipherId}`);
}
const lastKnownRevisionDate = cipher.revisionDate;

💭 Questions for Author

  1. Missing Jira ticket: What ticket do these vault changes belong to?
  2. API contract: Does the server-side API expect this field? Is it optional or required?
  3. Testing: Are there tests for the error cases (cipher not found, null dates)?
  4. Backwards compatibility: What happens if server doesn't support this field yet?

📋 Action Items for Author

High Priority

  1. Split this PR - Move vault changes to a separate PR with proper ticket reference
  2. Test with disableClose: true - Verify focus behavior when close button is hidden
  3. Add null checks - In vault code for cipher lookup and date handling

Medium Priority

  1. Document focus behavior - Add JSDoc comments explaining the focus strategy
  2. Test with screen readers - Verify accessibility impact of focusing close button first
  3. Consider configurability - Evaluate if focus target should be configurable per dialog

Low Priority

  1. Add unit tests - For focus behavior in dialog component
  2. Update PR description - Clarify which changes belong to PM-24178

🎯 Recommendation

Do not merge until the unrelated vault changes are separated into their own PR. The dialog focus change itself is simple and looks reasonable, but it's bundled with unrelated changes that need separate review and testing.

Once split:

  • Dialog PR: Needs accessibility testing and documentation
  • Vault PR: Needs null safety fixes and proper tests

@github-actions
Copy link
Contributor

github-actions bot commented Oct 16, 2025

Logo
Checkmarx One – Scan Summary & Details7d4c480c-251c-49e4-8b29-0a497bb73f5f

Great job! No new security vulnerabilities introduced in this pull request

@codecov
Copy link

codecov bot commented Oct 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 39.15%. Comparing base (df1dd16) to head (b123c7e).
⚠️ Report is 198 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #16896      +/-   ##
==========================================
- Coverage   39.16%   39.15%   -0.01%     
==========================================
  Files        3449     3449              
  Lines       97916    97916              
  Branches    14726    14726              
==========================================
- Hits        38348    38342       -6     
- Misses      57898    57905       +7     
+ Partials     1670     1669       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nikwithak nikwithak force-pushed the vault/PM-24178/fix-modal-focus branch from 70bc198 to b123c7e Compare October 16, 2025 00:19
@sonarqubecloud
Copy link

@nikwithak nikwithak closed this Oct 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants